﻿using System;
using System.Collections.Generic;
using System.Linq;
using MathService.Values;

namespace MathService.Statistic
{
    public sealed class Histogram
    {
        public readonly double[] Argument;
        private readonly Interval[] f_Intervals;
        private readonly double f_Normalizator;
        public readonly double Max;
        public readonly double Min;
        public readonly int N;
        public readonly double[] Values;

        public Histogram(double[] X, int IntervalsCount)
        {
            N = X.Length;
            var lv_MinMax = new MinMaxValue();
            X.Foreach(lv_MinMax.AddValue);
            Max = lv_MinMax.Max;
            Min = lv_MinMax.Min;
            var dx = (Max - Min) / IntervalsCount;
            f_Intervals = new Interval[IntervalsCount].Initialize(i => new Interval(Min + (i * dx), true, Min + ((i + 1) * dx)));
            f_Intervals[IntervalsCount - 1].MaxInclude = true;
            Argument = f_Intervals.Select(I => I.Middle).ToArray();
            Values = new double[IntervalsCount];
            Action<double> action = x => f_Intervals.Foreach((interval, i) => { if(interval.Check(x)) Values[i]++; });
            X.Foreach(action);
            Values.Divade(f_Normalizator = Values.GetIntegral(Argument));
        }

        public bool CheckDestribution(Func<double, double> F, double p, double alpha = 0.05)
        {
            var lv_P_theor = new double[Values.Length].Initialize(i =>
            {
                var interval = f_Intervals[i];
                return F.GetIntegralValue(interval.Min,
                                        interval.Max,
                                        interval.Length / 20);
            });

            var stat = Values.GetMultiplyed((f_Normalizator / (N))).Select((t, i) => (lv_P_theor[i] - t)).Select(
                (delta, i) => ((delta * delta) / lv_P_theor[i])).Sum();
            var lv_Quantile = SpecialFunctions.Distribution.Student.QuantileHi2(2, alpha);
            Console.WriteLine(stat < lv_Quantile);
            Console.ReadLine();
            return stat < lv_Quantile;
        }

        public KeyValuePair<double, double>[] GetValues()
        {
            return new KeyValuePair<double, double>[Values.Length].Initialize(
                i => new KeyValuePair<double, double>(Argument[i], Values[i]));
        }
    }
}

